package com.zack.util.nlp;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.ansj.domain.Result;
import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.ToAnalysis;

import com.zack.util.multitype.file.ReadAndWriteFileFromDirectory;

public class ANSJ_Token_Util {

    public Map<String, String> wordSpanMap = new LinkedHashMap<String, String>();

    /**
     * 传入一篇文档，获取整篇文档的分词list
     * 
     * @param dir
     * @param postFix
     */
    public List<Term> toTokenDirRtTermList(String dir, String postFix) {
        String dirPath = dir;
        String splitMarkBetLineInOneArticle = "";
        String splitMarkBetAriticles = "";
        boolean recursive = false;
        String text = ReadAndWriteFileFromDirectory.getContentFromWholeDirectory(dirPath, postFix,
                splitMarkBetLineInOneArticle, splitMarkBetAriticles, recursive);
        // 进行分词写入map中
        Result result = ToAnalysis.parse(text);
        List<Term> termList = result.getTerms();
        return termList;
    }

    /**
     * 传入一篇文档，获取整篇文档的分词与span <2-3,你好> key不能重复
     * 
     * @param dir
     * @param postFix
     */
    public void toTokenDirIntoMap(String dir, String postFix) {
        String dirPath = dir;
        String splitMarkBetLineInOneArticle = "";
        String splitMarkBetAriticles = "";
        boolean recursive = false;
        String text = ReadAndWriteFileFromDirectory.getContentFromWholeDirectory(dirPath, postFix,
                splitMarkBetLineInOneArticle, splitMarkBetAriticles, recursive);
        // 进行分词写入map中
        Result result = ToAnalysis.parse(text);
        List<Term> termList = result.getTerms();
        for (Term term : termList) {
            String span = term.getOffe() + "-" + (term.getOffe() + term.getName().length());
            this.wordSpanMap.put(span, term.getName());
        }

    }

    /**
     * 过滤list中的term，如果任何一个term或者多个term组成的词在指定词典里面出现，就把这些term删除。 过滤termList,
     * 如果termList中连续term组成的词语在词典中就从termList里面删除这个词。 例如 list中是 你们 去 哪里 玩 游戏 了
     * 
     * 如果在词典中有词： 你们去， 哪里玩， 那么最后返回的termList就剩下： 游戏， 了 这两个term
     * 
     * @param termList
     * 
     */
    public void filterTermListAccorDict(List<Term> termList, String dictPath, boolean longIsBetter) {
        for (int i = 0; i < termList.size(); i++) {
            int num = i;
            boolean isWordOrPrefixInDict = true;
            String wordStr = termList.get(i).getName();
            String tempWord = "";
            int newBegin = termList.get(num).getOffe();
            int newEnd = newBegin + wordStr.length();
            int tempEnd = newBegin;
            boolean fromDict = false;
            while (isWordOrPrefixInDict && num < termList.size()) {
                tempEnd = tempEnd + termList.get(num).getName().length();
                tempWord = tempWord + termList.get(num).getName();
                int code = searchWordInDict(tempWord, dictPath);
                if (code == 1) { // 如果找到这个词
                    wordStr = tempWord;
                    newEnd = tempEnd;
                    i = num;
                    fromDict = true;
                    if (!longIsBetter) {
                        // 如果没有开启长词优先，就按照找到的第一个词，进行输出，所以跳出去。
                        break;
                    }
                } else if (code == 0) {// 如果词典里面有这个词根
                    // 继续
                } else {// 如果词典里面即没有这个词也没有这个词根
                    isWordOrPrefixInDict = false;
                }
                num++;
            }
            if (fromDict) {// 如果找到了一个长词在词典中，根据这个长词的的span来把里面的每个子词删除掉。
                int countDelete = removeTermFromTermList(termList, newBegin, newEnd, false);
                i = i - countDelete;
            }
        }
    }

    /**
     * 传入一个 termList, 以及span的的begin与end， 把termList中在这个范围之内的都给去除。 提供两种模式： 1. 普通模式： 例如
     * begin =5 end =9, listTerm中有 你好 4-5 ， 来自 5-7， 哪里 7-9 这样只能删除 来自哪里， 而无法删除你好， 因为
     * 你好 这个分词只有一部分在listTerm中 2. 强力模式： 会把上面例子中的你好也给删除，因为 它的end在 范围内，虽然begin不在范围里面
     * 
     * @param termList
     * @param begin
     * @param end
     * 
     *            返回一共删除了几个term
     */
    public static int removeTermFromTermList(List<Term> termList, int begin, int end, boolean ifStrong) {
        int deleteFrom = 0;
        int numNeedDeete = 0;
        System.out.println("begin: " + begin + "   end: " + end);
        for (int k = 0; k < termList.size(); k++) {
            int endCurr = termList.get(k).getOffe() + termList.get(k).getName().length();
            int beginCurr = termList.get(k).getOffe();

            if (endCurr < begin) {
                continue;
            }
            if (beginCurr > end) {
                break;
            }
            // 如果开启了强力模式：
            if (ifStrong) {
                if (beginCurr <= begin && endCurr >= begin && endCurr <= end) {
                    numNeedDeete++;
                    if (numNeedDeete == 1) {
                        deleteFrom = k;
                    }
                } else if (beginCurr >= begin && endCurr >= end && beginCurr <= end) {
                    numNeedDeete++;
                    if (numNeedDeete == 1) {
                        deleteFrom = k;
                    }
                } else if (beginCurr >= begin && endCurr <= end) {
                    numNeedDeete++;
                    if (numNeedDeete == 1) {
                        deleteFrom = k;
                    }
                }
            } else {// 没有开启强力模式
                    // 如果在里面就删除
                if (beginCurr >= begin && endCurr <= end) {
                    numNeedDeete++;
                    if (numNeedDeete == 1) {
                        deleteFrom = k;
                    }
                }
            }
        }
        for (int x = 0; x < numNeedDeete; x++) {
            termList.remove(deleteFrom);
        }
        return numNeedDeete;
    }

    /**
     * 组合分好的词，返回map。 把已经分好的词语， 进行基于词典的进一步组合。 组合后重新写入map 例如 本来是 你， 好，啊， 发现词典里有词语： 你好，
     * 那么我们就组合成 你好。 返回的map: <span, 你好> <span, 啊>
     * 
     * @param tokenMap
     *            <span, word>
     * @param dictPath
     */
    public Map<String, String> toGroupWordsAccDict(List<Term> termList, String dictPath, boolean longIsBetter) {
        Map<String, String> spanWordMap = new LinkedHashMap<String, String>();
        for (int i = 0; i < termList.size(); i++) {
            int num = i;
            boolean isWordOrPrefixInDict = true;
            String wordStr = termList.get(i).getName();
            String tempWord = "";
            int newBegin = termList.get(num).getOffe();
            int newEnd = newBegin + wordStr.length();
            int tempEnd = newBegin;
            while (isWordOrPrefixInDict && num < termList.size()) {
                tempEnd = tempEnd + termList.get(num).getName().length();
                tempWord = tempWord + termList.get(num).getName();
                int code = searchWordInDict(tempWord, dictPath);
                if (code == 1) { // 如果找到这个词
                    wordStr = tempWord;
                    newEnd = tempEnd;
                    i = num;
                    if (!longIsBetter) {
                        // 如果没有开启长词优先，就按照找到的第一个词，进行输出，所以跳出去。
                        break;
                    }
                } else if (code == 0) {// 如果词典里面有这个词根
                    // 继续
                } else {// 如果词典里面即没有这个词也没有这个词根
                    isWordOrPrefixInDict = false;
                }
                num++;
            }
            String span = newBegin + "-" + newEnd;
            spanWordMap.put(span, wordStr);
        }
        return spanWordMap;
    }

    /**
     * 传入一个单词和一个词典， 判断单词是否出现在词典中。 有三种情况：
     * 
     * 单词没有出现在词典中 返回 -1 单词作为词缀出现在词典中 返回 0 单词出现在词典中 返回 1
     * 
     * @return
     */
    private int searchWordInDict(String word, String dictPath) {
        // TODO Auto-generated method stub
        List<String> dictList = new ArrayList<String>();
        dictList.add("郑哲副");
        dictList.add("郑哲副主任医师");
        dictList.add("患者目前");
        dictList.add("患者目前恢复可");
        dictList.add("出入量");
        dictList.add("电解质");

        for (String eachW : dictList) {
            if (eachW.startsWith(word) && (!eachW.equals(word))) {
                return 0;
            } else if (eachW.equals(word)) {
                return 1;
            }
        }
        return -1;
    }

}
